'use strict';

module.exports = core;
  const path = require('path')
// 外部依赖写在上面，内部依赖写在下面
const semver = require("semver")
const colors = require('colors')
const commander = require('commander')
const pathExists = require('path-exists').sync
const userHome = require('user-home')

const pkg = require("../package.json")
let args, config
// checkInputArgs()// 因为修改log了，所以需要在初始化log的前面，因为require是同步的方法
const log = require("@cli-dev/log")
const exec = require('@cli-dev/exec')
const constant = require('./constant');
const program =  new commander.Command() // 实例化一个对象




async function core() {
    try{
        /** 第一阶段
         * 1.检查版本号
         * 2.检查node版本，用semver
         * 3. 检查root启动 ，用root-check库
         * 4. 检查用户主目录， 用user-home库
         * 5.检查入参，用户注册脚手架的检查，对入参数进行检查options,看是否需要进入调试模式，
         * 默认是没有vsebose模式，需要--debug，所以需要全局监听是否有--debug这个命令，
         * 如果有，就需要对log进行设置log level. 用minimist库来解析输入的参数
         * 6.检查环境变量： 在操作系统中配置一些环境变量， 然后将我们的用户的一些登录信息，敏感信息保存在本地，
         * 而不用集成在代码当中，我们需要的时候，就可以实时读取。 用dotenv这个库来实现，判断当前是否有，
         * 没有的话，生成一个默认的config配置，并且将这个配置的值存在process.env.xx,这个xx是自己定义的一个key值，之后用process.env来获取,相当于存在全局变量中
         * 7.检查当前是否为最新版本
         */
        prepare()

      /**
     * 第二阶段
     * 1. command命令注册
     */
      registerCommand()
    }catch(err){
        log.error(err.message)
        console.log(err,'出错了')

    }
  
}

function checkPkgVersion(){

    // console.log(pkg.version,'checkPkgVersion==', process.env.LOG_LEVEL)
}

function checkNodeVersion(){
    const currentVersion = process.version;
    // 第一步，获取当前的版本号
    // console.log(process.version)
    // 第二步，比对最低版本号
    const lowestVersion = constant.LOWEST_NODE_VERSION
    // 用semver来比对版本号
    if(!semver.gte(currentVersion, lowestVersion)) {
        throw new Error(colors.red(`hx-cli 需要安装v${lowestVersion}以上版本的nodejs`))
    }
}


function checkRoot(){
    //  501 表示当前登录用户， 0表示超级管理员
  const rootCheck = require("root-check")
  // 用sudo执行命令，但是用来root-check库之后，process.geteuid()输出为501，
//   root-check 2.x不支持require的方式引入，需要es6的import方式引入
//   console.log(process.geteuid(),)
  rootCheck()
}



function checkUserHome(){
    // 拿到用户的主目录
    if(!userHome || !pathExists(userHome)){
        // 如果拿不到用户主目录，就直接抛出异常， 因为后面需要用户主目录进行缓存
        throw new Error(colors.red('当前登录用户主目录不存在！'))
    }
}


// 参数检查不需要了
function checkInputArgs(){
    const minimist = require('minimist')
     args = minimist(process.argv.slice(2))
    checkArgs()
}


function checkArgs(){
    if(args.debug){
        // 输入命令行中带了--debug
        process.env.LOG_LEVEL = 'verbose' // 进行调试模式
    }else {
        process.env.LOG_LEVEL = 'info' // log level默认是info

    }
    log.level = process.env.LOG_LEVEL

}

function checkEnv(){
    const dotenv = require('dotenv')
    const dotenvPath = path.resolve(userHome,'.env')
    // console.log(pathExists(dotenvPath),'pathExists(dotenvPath)=', dotenvPath)
    if(pathExists(dotenvPath)){
            // 如果有，则执行，自己可以通过在~目录，vim .env自己添加参数，添加的参数，可以通过process.env.xxx获取
            // 如果没有，需要创建默认的一个config
       config = dotenv.config({
            path: path.resolve(userHome,'.env')
        })
    }
   createDefaultConfig()
    // log.verbose(JSON.stringify(config),'环境变量',process.env.CLI_HOME_PATH)
}

function createDefaultConfig(){
    const cliConfig = {
        home: userHome,
    }
    if(process.env.CLI_HOME){
        cliConfig['cliHome'] = path.join(userHome, process.env.CLI_HOME)
    }else {
        cliConfig['cliHome'] = path.join(userHome, constant.DEFAULT_CLI_HOME)
    }
    process.env.CLI_HOME_PATH = cliConfig.cliHome
    // return cliConfig

}

async function checkGlobalUpdate(){
    // 浏览器打开https://registry.npmjs.org/你发布的包的名字name,就可以看到所有发布的版本
    // 1.获取当前版本号和模块名
    // 2. 调用npm API,获取所有的版本号
    // 3. 获取所有的版本号，比对哪些版本号是大于当前版本号的
    // 4. 获取最新的版本号，提示用户更新到该版本，
    const currentVersion= pkg.version
    const npmName = pkg.name
    log.verbose('npmName',npmName)
   
    const { getNpmVersions, getNpmSemverVersion} = require('@cli-dev/get-npm-info')
  
  const lastVersion = await getNpmSemverVersion(currentVersion, npmName)
//   if(lastVersion && semver.gt(lastVersion, currentVersion)) {
//       log.warn('更新提示',colors.yellow(`请手动更新${npmName},当前版本${currentVersion}, 最新版本${lastVersion}
//       更新命令：npm install -g ${npmName}
//       `))
//   }
}

 async function prepare(){
    checkPkgVersion() // 检查版本号
    checkNodeVersion() // 检查node版本 
    checkRoot()// 检查root启动,判断当前用户是否有权限，如果没有权限进行降级 ,在做脚手架的时候，需要去做降级
    // 如果是root文件，我们既不能删，也不能写 可能还没有读写权限  root-check这个库， 会判断是否是root用户，如果是，会自动帮我们降级
    checkUserHome()
    // checkInputArgs()
    checkEnv()
  await  checkGlobalUpdate()
}

function registerCommand(){
    program
    .name(Object.keys(pkg.bin)[0])
    .usage('<command> [options]')
     .version(pkg.version)
     .option('-d, --debug', '是否开启调试模式', false)
     .option('-tp, --targetPath <targetPath>', '是否开启指定本地调试文件路径', '')

     // commander命令处理
     program
      .command('init [projectName]')
      .option('-f, --force','是否强制初始化项目')
      .action( exec)

      program.on('option:targetPath', function(){
        let options = program.opts() // 注意不同版本的获取不一样
        if(options.targetPath){
            process.env.CLI_TARGET_PATH = options.targetPath
        }
      })

     // 开启debug模式
     program.on('option:debug', function() {
         let options = program.opts() // 注意不同版本的获取不一样
         if(options.debug){
            // 开启这个监听之后，我们之后就要把 执行过程移植到命令当中去，即在注册命令之后，再去执行core函数里面的
            process.env.LOG_LEVEL = 'verbose'
        }else {
            process.env.LOG_LEVEL = 'info'
        }
        log.level = process.env.LOG_LEVEL
      });

      // 对未知命令的监听
      program.on('command:*', function(obj){
          const availableCommands = program.commands.map(cmd => cmd.name)
          console.log(colors.red('未知命令'+ obj[0]))
          if(availableCommands.length){
               console.log(colors.red('可用命令：'+ availableCommands.join(',')))
          }

      })
      if(process.args && process.args.length < 1){
        //   说明没有输入任何命令,给出help命令
        program.outputHelp()
        console.log()

      }
      program.parse(process.argv)
}



